#ifndef __BLINDDEL_H__
#define __BLINDDEL_H__

enum { MAX_VTABLE_ENTRIES  = 1024 };
// standard vtable entry declare
typedef void (_stdcall *VTBL_ENTRY)();
typedef VTBL_ENTRY VTABLE[MAX_VTABLE_ENTRIES];

extern const VTABLE g_bdvtbl;

struct _BlindDelegator;
typedef ULONG (_stdcall* DestroyBlindDelegator)(_BlindDelegator* pBlindDel, IUnknown** punkInner, IUnknown** punkOuter);

extern void _stdcall MinimalDestruct(_BlindDelegator* pBlindDel);

struct _BlindDelegator
{
    const VTABLE           *m_pVTable;    // VTable pointer
    IUnknown               *m_punkInner;  // Object delegated to (keep at offset 4)
    IUnknown               *m_punkOuter;  // Owning IUnknown
    ULONG                   m_dwRefs;     // The ref count for this object
    DestroyBlindDelegator   m_pfnDestroy; // The function to call on destruction instead of delete

    ULONG DestroyThis();

    static inline _BlindDelegator *This(void *pvThis) 
    { 
        return (_BlindDelegator*)(LPBYTE(pvThis) - offsetof(_BlindDelegator, m_pVTable)); 
    }

    //static HRESULT STDMETHODCALLTYPE QueryInterface(IUnknown *pvThis, REFIID riid, void **ppvObj)
    //{
    //    return This(pvThis)->m_punkOuter->QueryInterface(riid, ppvObj);
    //}

    static ULONG STDMETHODCALLTYPE AddRef(IUnknown *pvThis)
    {
        return ++(This(pvThis)->m_dwRefs);
    }

    inline ULONG STDMETHODCALLTYPE _Release()
    {
        if (0 == --m_dwRefs)
        {
            return DestroyThis();
        }
        return m_dwRefs;
    }

    static ULONG STDMETHODCALLTYPE Release(IUnknown *pvThis)
    {
        return This(pvThis)->_Release();
    }

    // Create a blind or callback delegator
    static HRESULT CreateDelegator(IUnknown *punkOuter, IUnknown *punkDelegatee, const IID* piid, _BlindDelegator* pEmbeddedThis, DestroyBlindDelegator pfnDestroy, IUnknown **ppvObj);
};
#endif  //__BLINDDEL_H__
